#pragma once

#include<iostream>
#include<vector>
#include<assert.h>
#include<string.h>

#define BUFFER_DEFAULT_SIZE 1024
class Buffer{
public:
    Buffer():_reader_idx(0),_writer_idx(0),_buffer(BUFFER_DEFAULT_SIZE){}//千万别忘了写构造初始化列表，不然会出现随机数有时候成功有时候失败
    ~Buffer(){}
    //获取当前写入起始位置
    char *Begin(){return &*_buffer.begin();} 
    char *WritePosition(){return Begin()+_writer_idx;}
    //获取当前读取起始位置
    char *ReadPosition(){return Begin()+_reader_idx;}
    //获取缓冲区末尾空闲空间大小--写偏移之后的空间
    uint64_t TailIdleSize(){return _buffer.size()-_writer_idx;}
    //获取缓冲区起始空闲空间大小--读偏移之前的空间
    uint64_t HeadIdleSize(){return _reader_idx;}
    //获取可读数据大小=写偏移-读偏移
    uint64_t ReadAlbeSize(){return _writer_idx-_reader_idx;}
    //将读偏移向后移动---读了多少移动多少
    void MoveReadOffset(uint64_t len){
        if(len==0) return;
        //向后移动的大小，必须小于可读数据大小
        assert(len<=ReadAlbeSize());
        _reader_idx+=len;
    }
    //将写偏移向后移动
    void MoveWriteOffset(uint64_t len){
        assert(len<=TailIdleSize());
        _writer_idx+=len;
    }
    //确保可写空间足够（整体空闲空间够了就移动数据，否则就扩容）
    void EnsureWriteSpace(uint64_t len){
        if(TailIdleSize()>=len) return;//如果末尾空闲空间足够，直接返回
        //末尾空间不够，则判断加上起始位置的空闲空间大小是否足够，足够就将数据移动到起始
        if(len<=TailIdleSize()+HeadIdleSize()){
            uint64_t rsz=ReadAlbeSize();//把当前数据大小先保存起来
            std::copy(ReadPosition(),ReadPosition()+rsz,Begin());
            _reader_idx=0;//将读偏移归零
            _writer_idx=rsz;//将写位置置为可读数据大小，因为当前的可读数据大小就是写偏移量
        }else{
            //总体空间不够，不移动数据，直接写偏移之后扩容足够空间
            _buffer.resize(_writer_idx+len);
        }
    }
    //写入数据（输入型） 
    void Write(const void* data,uint64_t len){
        //1.保证有足够空间  2.拷贝数据进去
        EnsureWriteSpace(len);
        const char* d=(const char*)data;
        std::copy(d,d+len,WritePosition());
    }
    void WriteAndPush(const void* data,uint64_t len){
        Write(data,len);
        MoveWriteOffset(len);
    }
    void WriteString(const std::string&  data){
        return Write(data.c_str(),data.size());
    }
    void WriteStringAndPush(const std::string&  data){
        WriteString(data);
        MoveWriteOffset(data.size());
    }
    void WriteBuffer(Buffer&data){
        return Write(data.ReadPosition(),data.ReadAlbeSize());
    }
    void WriteBufferAndPush(Buffer&data){
        WriteBuffer(data);
        MoveWriteOffset(data.ReadAlbeSize());
    }
    //读取数据(输出型)
    void Read(void* buffer,uint64_t len){
        //要获取的数据必须小于可读数据大小
        assert(len<=ReadAlbeSize());
        std::copy(ReadPosition(),ReadPosition()+len,(char*)buffer);//保持类型的统一
    }
    void ReadAndPop(void* buf,uint64_t len){
        Read(buf,len);
        MoveReadOffset(len);
    }
    std::string ReadAsString(uint64_t len){
        assert(len<=ReadAlbeSize());
        std::string str;
        str.resize(len);
        Read(&str[0],len);
        return str;
    }
    std::string ReadAsString_AndPop(uint64_t len){
        assert(len<=ReadAlbeSize());
        std::string str=ReadAsString(len);
        MoveReadOffset(len);
        return str;
    }
    char *FindCRLF(){
        void* res=memchr(ReadPosition(),'\n',ReadAlbeSize());
        return (char*)res;
    }
    std::string Getline(){
        char* pos =FindCRLF();
        if(pos==nullptr) return "";
        return ReadAsString(pos-ReadPosition()+1);//+1是为了把换行字符也取出来
    }
    std::string GetLineAndPop(){
        std::string str=Getline();
        MoveReadOffset(str.size());
        return str;
    }
    //清空缓冲区
    void Clear(){
        //只需要将偏移量归0即可
        _reader_idx=0;
        _writer_idx=0;
    }
    

private:
    std::vector<char> _buffer;//使用vectors进行内存空间管理
    uint64_t _reader_idx;//读偏移
    uint64_t _writer_idx;//写偏移
};